#include "tcp_server_base.h"
#include "../logger/logger.h"

//////////////////////////////////////////////////////////////////////////
//
tcp_server_base_t::tcp_server_base_t( tcp_base_port_t const& port ) 
	: server_( port
		, std::tr1::bind( &tcp_server_base_t::accepted, this, std::tr1::placeholders::_1 )
		, std::tr1::bind( &tcp_server_base_t::recved, this, std::tr1::placeholders::_1, std::tr1::placeholders::_2, std::tr1::placeholders::_3 )
		, std::tr1::bind( &tcp_server_base_t::disconnected, this, std::tr1::placeholders::_1 ) )
	, port_(port)
{
	//#define register_tcp_base_dispatcher(packet_id_name) \
	//	packet_dispatchers_[recv_packet_id_e::##packet_id_name] = std::tr1::bind(&game_server_t::dispatch_##packet_id_name, this, std::tr1::placeholders::_1, std::tr1::placeholders::_2);

	//register_tcp_base_dispatcher( login );
	//register_tcp_base_dispatcher(logout);
	//register_tcp_base_dispatcher(make_stage);
	//register_tcp_base_dispatcher(join_stage);
	//register_tcp_base_dispatcher(leave_stage);
	//register_tcp_base_dispatcher(start_stage);
	//register_tcp_base_dispatcher(update_stage);
	//register_tcp_base_dispatcher(end_stage);
	//
	//#undef register_tcp_base_dispatcher

	register_on_accept_callback([this](connection_t const* conn) { on_accept(conn); });
	register_on_close_callback([this](connection_t const* conn) { on_disconnect(conn); });
}

//////////////////////////////////////////////////////////////////////////
//
tcp_server_base_t::~tcp_server_base_t()
{

}

//////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::accepted( connection_t* conn )
{
	if(conn == nullptr)
		return;

	connections_.insert( std::make_pair( conn, connection_ptr(conn) ) );

	for each(auto callback in on_accept_callbacks_)
	{
		callback(conn);
	}
}

//////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::recved( connection_t* conn, char const * packet, size_t size )
{
	const size_t packet_id_length = sizeof(packet_id_t);

	if(conn == nullptr || packet == nullptr || size < packet_id_length)
		return;

	packet_id_t packet_id = *(packet_id_t*)packet;

	recv_packet_t recv_packet( packet_id, packet + packet_id_length, size - packet_id_length );

	process_packet( conn, recv_packet );
}

//////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::disconnected( connection_t* conn )
{
	if(conn == nullptr)
		return;

	for each(auto callback in on_close_callbacks_)
	{
		callback(conn);
	}

	connections_.erase(conn);
}

//////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::process_packet( connection_t* conn, recv_packet_t & packet )
{
	if( conn == nullptr )
		return;

	for each(auto callback in on_recv_callbacks_)
	{
		callback(conn);
	}

	packet_id_t packet_id = packet.packet_id();

	auto dispatcher = packet_dispatchers_.find(packet_id);

	if (dispatcher == packet_dispatchers_.end())
	{
		debug_logger << log_tag::error << L"invalid packet id : " << packet_id << std::endl;
		disconnected(conn);
		return;
	}

	dispatcher->second(conn, packet);
}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::send(connection_t const * conn, umtl::memory_stream& stream)
{
	char const * buffer = stream.begin_read_buffer();
	size_t buffer_size = (size_t)stream.tellp();
	server_.send(buffer, buffer_size);
}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::register_on_accept_callback(connection_event_t const& callback)
{
	on_accept_callbacks_.push_back(callback);
}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::register_on_recv_callback(connection_event_t const& callback)
{
	on_recv_callbacks_.push_back(callback);
}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::register_on_close_callback(connection_event_t const& callback)
{
	on_close_callbacks_.push_back(callback);
}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::on_accept(connection_t const* conn)
{

}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::on_disconnect(connection_t const* conn)
{

}

///////////////////////////////////////////////////////////////////////////////////
//
void tcp_server_base_t::register_dispatcher(packet_id_t packet_id, packet_dispatcher const& dispatcher)
{
	packet_dispatchers_[packet_id] = dispatcher;
}

///////////////////////////////////////////////////////////////////////////////////